use crate::db::db_classroom;
use crate::db::entities::classroom::Model;
use crate::rest_api::api_classroom::{Classroom, CreateParams, SearchParams, UpdateParams};

use anyhow::Result;

use rbase::define::{ApiError, BaseError};
use rbase::id_utils::str2id;
use rbase_iam::db::define::SYSTEM_ID;
use rbase_iam::rest_api::api_user::UserToken;

pub async fn find_classroom_by_id(user_token: &UserToken, classroom_id: &String) -> Result<Classroom, ApiError> {
    let classroom_model = db_classroom::find_by_id_and_owner_ids(str2id(classroom_id)?, &user_token.owner_ids)
        .await?
        .ok_or_else(|| BaseError::ResourceNotFound(classroom_id.to_string()))?;
    Ok(Classroom::from_model(&classroom_model))
}

pub async fn delete_classroom_by_id(user_token: &UserToken, classroom_id: &String) -> Result<(), ApiError> {
    let classroom_model = db_classroom::find_by_id_and_owner_ids(str2id(classroom_id)?, &user_token.owner_ids)
        .await?
        .ok_or_else(|| BaseError::ResourceNotFound(classroom_id.to_string()))?;
    // 普通用户不能修改系统资源
    if !user_token.is_admin && classroom_model.owner_id == Some(SYSTEM_ID) {
        return Err(BaseError::PermissionDenied.into());
    }
    db_classroom::delete_by_id(classroom_model.id).await?;
    Ok(())
}

pub async fn update_classroom_by_id(user_token: &UserToken, classroom_id: &String, new_classroom: &UpdateParams) -> Result<(), ApiError> {
    let old_model = db_classroom::find_by_id_and_owner_ids(str2id(classroom_id)?, &user_token.owner_ids)
        .await?
        .ok_or_else(|| BaseError::ResourceNotFound(classroom_id.to_string()))?;
    // 普通用户不能修改系统资源
    if !user_token.is_admin && old_model.owner_id == Some(SYSTEM_ID) {
        return Err(BaseError::PermissionDenied.into());
    }
    let new_model = Model {
        id: old_model.id,
        name: Some(new_classroom.name.clone()),
        grade: Some(new_classroom.grade.clone()),
        class: Some(new_classroom.class.clone()),
        ..Default::default()
    };
    db_classroom::update(new_model).await?;
    Ok(())
}

pub async fn create_classroom(user_token: &UserToken, new_classroom: &CreateParams) -> Result<Classroom> {
    let new_model = Model {
        name: Some(new_classroom.name.clone()),
        grade: Some(new_classroom.grade.clone()),
        class: Some(new_classroom.class.clone()),
        owner_id: Some(user_token.id),
        ..Default::default()
    };
    let created_model = db_classroom::insert(new_model).await?;
    Ok(Classroom::from_model(&created_model))
}

pub async fn search(user_token: &UserToken, classroom_search_params: &SearchParams) -> Result<(Vec<Classroom>, i64)> {
    let (classrooms, total) = db_classroom::search(&db_classroom::SearchParams {
        name: classroom_search_params.name.clone(),
        offset: classroom_search_params.offset,
        limit: classroom_search_params.limit,
        order_by: classroom_search_params.order_by.clone(),
        order: classroom_search_params.order.clone(),
        owner_ids: user_token.owner_ids.clone(),
    })
    .await?;
    Ok((classrooms.into_iter().map(|classroom| Classroom::from_model(&classroom)).collect(), total))
}
